package logger

import (
	"os"
	"path/filepath"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

// Logger 日志接口 - 只保留8个核心方法
type Logger interface {
	// 基础日志方法 (4个)
	Debug(msg string)
	Info(msg string)
	Warn(msg string)
	Error(msg string)

	// 格式化日志方法 (4个)
	Debugf(format string, args ...interface{})
	Infof(format string, args ...interface{})
	Warnf(format string, args ...interface{})
	Errorf(format string, args ...interface{})

	// 实用方法 (2个)
	With(fields map[string]interface{}) Logger
	Named(name string) Logger
	WithRequestID(c interface{}) Logger
}

// LogConfig 日志配置 - 支持环境差异化
type LogConfig struct {
	// 基础配置
	Level  string `json:"level"`  // debug/info/warn/error
	Format string `json:"format"` // console/json
	Output string `json:"output"` // console/file/both

	// 文件配置 (仅当output包含file时生效)
	Filename   string `json:"filename"`    // 日志文件路径
	MaxSize    int    `json:"max_size"`    // 单文件最大大小(MB)
	MaxAge     int    `json:"max_age"`     // 保留天数
	MaxBackups int    `json:"max_backups"` // 最大备份数
	Compress   bool   `json:"compress"`    // 是否压缩
}

// zapLogger zap实现的日志器
type zapLogger struct {
	logger *zap.Logger
}

// NewLogger 创建简化日志实例，支持环境差异化配置
func NewLogger(config *LogConfig) (Logger, error) {
	// 解析日志级别
	level, err := zapcore.ParseLevel(config.Level)
	if err != nil {
		level = zapcore.InfoLevel
	}

	// 创建编码器配置
	encoderConfig := getEncoderConfig(config.Format)

	// 创建编码器
	var encoder zapcore.Encoder
	if config.Format == "json" {
		encoder = zapcore.NewJSONEncoder(encoderConfig)
	} else {
		encoder = zapcore.NewConsoleEncoder(encoderConfig)
	}

	// 创建写入器
	writer := getWriter(config)

	// 创建核心
	core := zapcore.NewCore(encoder, writer, level)

	// 创建logger（简化选项）
	logger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1))

	return &zapLogger{logger: logger}, nil
}

// NewEnvironmentLogger 根据环境自动创建日志实例
func NewEnvironmentLogger(environment string) (Logger, error) {
	var config *LogConfig

	switch environment {
	case "production":
		// 生产环境：文件日志，JSON格式，INFO级别
		config = &LogConfig{
			Level:  "info",
			Format: "json",
			Output: "file",
			// 文件配置需要通过 NewEnvironmentLoggerWithConfig 传入
			Filename:   "./storage/logs/app.log", // 临时默认值
			MaxSize:    50,                       // 临时默认值
			MaxAge:     30,                       // 临时默认值
			MaxBackups: 10,                       // 临时默认值
			Compress:   true,                     // 临时默认值
		}
	default: // development
		// 开发环境：控制台日志，彩色格式，DEBUG级别
		config = &LogConfig{
			Level:  "debug",
			Format: "console",
			Output: "console",
		}
	}

	// 支持环境变量覆盖关键配置
	if logLevel := os.Getenv("LOG_LEVEL"); logLevel != "" {
		config.Level = logLevel
	}
	if logOutput := os.Getenv("LOG_OUTPUT"); logOutput != "" {
		config.Output = logOutput
	}

	return NewLogger(config)
}

// NewEnvironmentLoggerWithConfig 根据环境和配置创建日志实例
func NewEnvironmentLoggerWithConfig(environment string, logConfig interface{}) (Logger, error) {
	var config *LogConfig

	switch environment {
	case "production":
		// 生产环境：文件日志，JSON格式，INFO级别，使用配置文件参数
		config = &LogConfig{
			Level:  "info",
			Format: "json",
			Output: "file",
		}

		// 根据传入配置的类型来读取文件配置
		if cfg, ok := logConfig.(map[string]interface{}); ok {
			// 从config.LogConfig读取
			if filename, exists := cfg["filename"]; exists {
				if filenameStr, ok := filename.(string); ok {
					config.Filename = filenameStr
				}
			}
			if maxSize, exists := cfg["max_size"]; exists {
				if maxSizeInt, ok := maxSize.(int); ok {
					config.MaxSize = maxSizeInt
				}
			}
			if maxAge, exists := cfg["max_age"]; exists {
				if maxAgeInt, ok := maxAge.(int); ok {
					config.MaxAge = maxAgeInt
				}
			}
			if maxBackups, exists := cfg["max_backups"]; exists {
				if maxBackupsInt, ok := maxBackups.(int); ok {
					config.MaxBackups = maxBackupsInt
				}
			}
			if compress, exists := cfg["compress"]; exists {
				if compressBool, ok := compress.(bool); ok {
					config.Compress = compressBool
				}
			}
		}

		// 设置默认值以防配置缺失
		if config.Filename == "" {
			config.Filename = "./storage/logs/app.log"
		}
		if config.MaxSize == 0 {
			config.MaxSize = 50
		}
		if config.MaxAge == 0 {
			config.MaxAge = 30
		}
		if config.MaxBackups == 0 {
			config.MaxBackups = 10
		}

	default: // development
		// 开发环境：控制台日志，彩色格式，DEBUG级别
		config = &LogConfig{
			Level:  "debug",
			Format: "console",
			Output: "console",
		}
	}

	// 支持环境变量覆盖关键配置
	if logLevel := os.Getenv("LOG_LEVEL"); logLevel != "" {
		config.Level = logLevel
	}
	if logOutput := os.Getenv("LOG_OUTPUT"); logOutput != "" {
		config.Output = logOutput
	}

	return NewLogger(config)
}

// getEncoderConfig 获取简化的编码器配置
func getEncoderConfig(format string) zapcore.EncoderConfig {
	config := zapcore.EncoderConfig{
		TimeKey:        "time",
		LevelKey:       "level",
		NameKey:        "logger",
		CallerKey:      "caller",
		MessageKey:     "msg",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.LowercaseLevelEncoder,
		EncodeTime:     zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05.000"),
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}

	if format == "console" {
		// 控制台格式：彩色输出，易读时间格式
		config.EncodeLevel = zapcore.CapitalColorLevelEncoder
		config.EncodeTime = zapcore.TimeEncoderOfLayout("15:04:05.000")
	}

	return config
}

// getWriter 获取简化的写入器
func getWriter(config *LogConfig) zapcore.WriteSyncer {
	switch config.Output {
	case "console":
		return zapcore.AddSync(os.Stdout)
	case "file":
		return getFileWriter(config)
	case "both":
		fileWriter := getFileWriter(config)
		return zapcore.NewMultiWriteSyncer(
			zapcore.AddSync(os.Stdout),
			fileWriter,
		)
	default:
		return zapcore.AddSync(os.Stdout)
	}
}

// getFileWriter 获取简化的文件写入器
func getFileWriter(config *LogConfig) zapcore.WriteSyncer {
	// 确保日志目录存在
	logDir := filepath.Dir(config.Filename)
	if err := os.MkdirAll(logDir, 0755); err != nil {
		// 如果创建目录失败，回退到当前目录
		config.Filename = filepath.Base(config.Filename)
	}

	lumberjackLogger := &lumberjack.Logger{
		Filename:   config.Filename,
		MaxSize:    config.MaxSize,
		MaxAge:     config.MaxAge,
		MaxBackups: config.MaxBackups,
		Compress:   config.Compress,
		LocalTime:  true,
	}

	return zapcore.AddSync(lumberjackLogger)
}

// 实现Logger接口

// 基础日志方法
func (l *zapLogger) Debug(msg string) {
	l.logger.Debug(msg)
}

func (l *zapLogger) Info(msg string) {
	l.logger.Info(msg)
}

func (l *zapLogger) Warn(msg string) {
	l.logger.Warn(msg)
}

func (l *zapLogger) Error(msg string) {
	l.logger.Error(msg)
}

// 格式化日志方法
func (l *zapLogger) Debugf(format string, args ...interface{}) {
	l.logger.Sugar().Debugf(format, args...)
}

func (l *zapLogger) Infof(format string, args ...interface{}) {
	l.logger.Sugar().Infof(format, args...)
}

func (l *zapLogger) Warnf(format string, args ...interface{}) {
	l.logger.Sugar().Warnf(format, args...)
}

func (l *zapLogger) Errorf(format string, args ...interface{}) {
	l.logger.Sugar().Errorf(format, args...)
}

// 实用方法
func (l *zapLogger) With(fields map[string]interface{}) Logger {
	zapFields := make([]zap.Field, 0, len(fields))
	for k, v := range fields {
		zapFields = append(zapFields, zap.Any(k, v))
	}
	return &zapLogger{logger: l.logger.With(zapFields...)}
}

func (l *zapLogger) Named(name string) Logger {
	return &zapLogger{logger: l.logger.Named(name)}
}

// === 便利函数 ===

// 全局日志实例（用于过渡期间）
var globalLogger Logger

// SetGlobalLogger 设置全局日志实例
func SetGlobalLogger(logger Logger) {
	globalLogger = logger
}

// GetGlobalLogger 获取全局日志实例
func GetGlobalLogger() Logger {
	if globalLogger == nil {
		// 如果没有设置全局日志，创建一个默认的开发环境日志
		logger, _ := NewEnvironmentLogger("development")
		globalLogger = logger
	}
	return globalLogger
}

// Debug 全局便利函数（保持简单）
func Debug(msg string) {
	GetGlobalLogger().Debug(msg)
}

func Info(msg string) {
	GetGlobalLogger().Info(msg)
}

func Warn(msg string) {
	GetGlobalLogger().Warn(msg)
}

func Error(msg string) {
	GetGlobalLogger().Error(msg)
}

func Debugf(format string, args ...interface{}) {
	GetGlobalLogger().Debugf(format, args...)
}

func Infof(format string, args ...interface{}) {
	GetGlobalLogger().Infof(format, args...)
}

func Warnf(format string, args ...interface{}) {
	GetGlobalLogger().Warnf(format, args...)
}

func Errorf(format string, args ...interface{}) {
	GetGlobalLogger().Errorf(format, args...)
}
